﻿using HartConfigTool.SerialPortUtil;
using HartConfigTool.UI;
using HartConfigTool.UI.ExpandControls;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using static HartConfigTool.HARTCommands.CMDs.CMD1ReadPV;

namespace HartConfigTool.HARTCommands.CMDs
{
    public class CMD0ReadUniqueIdentifier : CMDsBase
    {
        protected HARTCMD0ReadUniqueIdentifierStruct HARTCMD0ReadUniqueIdentifierCode;
        public Dictionary<string, IObserver> CMD0Observers;

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        public struct HARTCMD0ReadUniqueIdentifierStruct
        {
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
            public byte[] preamble;
            public byte start;
            public byte address;
            public byte cmd;
            public byte size;
            public byte parity;
        }

        public CMD0ReadUniqueIdentifier(SerialPortsManager serialPortManager)
        {
            ConfigurationParameters(serialPortManager);

            HARTCMD0ReadUniqueIdentifierCode = new HARTCMD0ReadUniqueIdentifierStruct()
            {
                preamble = new byte[5] { 0xff, 0xff, 0xff, 0xff, 0xff },
                start = 0x02,
                address = 0x80,
                cmd = 0x00,
                size = 0x00,
                parity = 0x82
            };

            CMD0Observers = new Dictionary<string, IObserver>();
        }
        protected override async Task SendCMDAsync()
        {
            byte[] tempAry = new byte[16];
            byte[] cmdCodeBytes = StructToBytes<HARTCMD0ReadUniqueIdentifierStruct>(HARTCMD0ReadUniqueIdentifierCode);

            Array.Copy(cmdCodeBytes, 5, tempAry, 0, 4);
            cmdCodeBytes[cmdCodeBytes.Length - 1] = HARTProtocolV7.GetCRC(tempAry, (byte)4);

#if DEBUG_MODE
            serialPortManager.DebugMessage("[" + DateTime.Now + "]:-->" + HARTProtocolV7.HexToString(cmdCodeBytes) + "\r\n");
#endif

            await serialPortManager.SendCMD(cmdCodeBytes);
        }
        protected virtual async Task SendCMDCode()
        {
            await serialPortManager.SendCMD(StructToBytes<HARTCMD0ReadUniqueIdentifierStruct>(HARTCMD0ReadUniqueIdentifierCode));
        }
        public override async Task ParseResponse(byte[] responseData)
        {
            await Task.Run(() =>
            {
                List<string> parts = new List<string>();
                byte[] bytes = null;
                byte[] data = null;
                IObserver observer = null;

                data = serialPortManager.GetRxBufferData();

                bytes = HARTProtocolV7.GetDataFrame(data);

#if DEBUG_MODE
                // Debug Message
                serialPortManager.DebugMessage("[" + DateTime.Now + "]:<--" + HARTProtocolV7.HexToString(data) + "\r\n");
#endif

                // HART Revision
                if (CMD0Observers.ContainsKey(ObserversInfo.HARTCMD0Observers["HART Rev"]))
                {
                    observer = CMD0Observers[ObserversInfo.HARTCMD0Observers["HART Rev"]];

                    if (observer is TextBoxUpdater)
                    {
                        parts.Clear();
                        parts.Add("0x" + bytes[10].ToString("X2"));
                        NotifyObservers(CMD0Observers, ObserversInfo.HARTCMD0Observers["HART Rev"], parts);
                    }
                }
                // Software Revision
                if (CMD0Observers.ContainsKey(ObserversInfo.HARTCMD0Observers["Software Rev"]))
                {
                    observer = CMD0Observers[ObserversInfo.HARTCMD0Observers["Software Rev"]];

                    if (observer is TextBoxUpdater)
                    {
                        parts.Clear();
                        parts.Add("0x" + bytes[12].ToString("X2"));
                        NotifyObservers(CMD0Observers, ObserversInfo.HARTCMD0Observers["Software Rev"], parts);
                    }
                }
                // Hardware Revision
                if (CMD0Observers.ContainsKey(ObserversInfo.HARTCMD0Observers["Hardware Rev"]))
                {
                    observer = CMD0Observers[ObserversInfo.HARTCMD0Observers["Hardware Rev"]];

                    if (observer is TextBoxUpdater)
                    {
                        parts.Clear();
                        parts.Add("0x" + ((bytes[13] & 0xf8) >> 3).ToString("X2")); // byte7, bit3~7
                        NotifyObservers(CMD0Observers, ObserversInfo.HARTCMD0Observers["Hardware Rev"], parts);
                    }
                }
                // Device ID
                if (CMD0Observers.ContainsKey(ObserversInfo.HARTCMD0Observers["Device ID"]))
                {
                    observer = CMD0Observers[ObserversInfo.HARTCMD0Observers["Device ID"]];

                    if (observer is TextBoxUpdater)
                    {
                        parts.Clear();
                        parts.Add("0x" + (((uint)bytes[15] << 16) + (((uint)bytes[16] << 8) + bytes[17])).ToString("X6"));
                        NotifyObservers(CMD0Observers, ObserversInfo.HARTCMD0Observers["Device ID"], parts);
                    }
                }
                // Manufacturer ID
                if (CMD0Observers.ContainsKey(ObserversInfo.HARTCMD0Observers["Manufacturer ID"]))
                {
                    observer = CMD0Observers[ObserversInfo.HARTCMD0Observers["Manufacturer ID"]];

                    if (observer is TextBoxUpdater)
                    {
                        parts.Clear();
                        parts.Add("0x" + (((ushort)bytes[23] << 8) + bytes[24]).ToString("X4"));
                        NotifyObservers(CMD0Observers, ObserversInfo.HARTCMD0Observers["Manufacturer ID"], parts);
                    }
                }

                this.serialPortManager.RxDataClear();
            });
        }
    }
}
